
package com.hexinfo.dmpro.dev.data.transfer.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hexinfo.dmpro.common.base.PageResult;
import com.hexinfo.dmpro.common.utils.CommonConstants;
import com.hexinfo.dmpro.component.file.transfer.model.FileTransfer;
import com.hexinfo.dmpro.component.file.transfer.service.FileTransferService;
import com.hexinfo.dmpro.data.transfer.common.common.enums.DataTransferTypeEnum;
import com.hexinfo.dmpro.data.transfer.common.model.*;
import com.hexinfo.dmpro.data.transfer.common.service.ICdhMetadataService;
import com.hexinfo.dmpro.data.transfer.common.service.IDataTransferTableFilterService;
import com.hexinfo.dmpro.data.transfer.common.service.IDateParatitionFieldMatchingService;
import com.hexinfo.dmpro.data.transfer.common.service.ISourceRuleTableViewService;
import com.hexinfo.dmpro.dev.data.transfer.common.enums.DevDataExportModelEnum;
import com.hexinfo.dmpro.dev.data.transfer.common.enums.DevDataTransferExportTaskStatusEnum;
import com.hexinfo.dmpro.dev.data.transfer.common.enums.DevDataTransferListStatusEnum;
import com.hexinfo.dmpro.dev.data.transfer.common.utils.FileTransferUtil;
import com.hexinfo.dmpro.dev.data.transfer.dao.DevDataExportTaskMapper;
import com.hexinfo.dmpro.dev.data.transfer.handle.IDevDataExportHandler;
import com.hexinfo.dmpro.dev.data.transfer.model.DevDataExportList;
import com.hexinfo.dmpro.dev.data.transfer.model.DevDataExportTask;
import com.hexinfo.dmpro.dev.data.transfer.model.FtpTakeUp;
import com.hexinfo.dmpro.dev.data.transfer.model.dto.DevDataExportCustomList;
import com.hexinfo.dmpro.dev.data.transfer.service.IDevDataExportListService;
import com.hexinfo.dmpro.dev.data.transfer.service.IDevDataExportTaskService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 总导出任务表
 *
 * @author yyh.huang
 * @date 2023-10-25 19:16:06
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
public class DevDataExportTaskServiceImpl extends ServiceImpl<DevDataExportTaskMapper, DevDataExportTask> implements IDevDataExportTaskService {

    private final DevDataExportTaskMapper devDataExportTaskMapper;

    private final ISourceRuleTableViewService sourceRuleTableViewService;

    private final IDevDataExportListService devDataExportListService;

    private final FileTransferService fileTransferService;

    private final ICdhMetadataService cdhMetadataService;

    private final IDataTransferTableFilterService dataTransferTableFilterService;

    private final IDevDataExportHandler devDataExportHandler;

    private final IDateParatitionFieldMatchingService datePartitionFieldMatchingService;

    @Value("${dev-data-ftp.server}")
    private String ftpServer;

    @Value("${dev-data-ftp.port}")
    private Integer ftpPort;

    @Value("${dev-data-ftp.user}")
    private String ftpUserName;

    @Value("${dev-data-ftp.password}")
    private String ftpPassword;

    @Value("${dev-data-ftp.space}")
    private String ftpSpace;

    @Value("${file.excelTemp}")
    String tempPath;

    /*
     * @Method: queryList <br>
     * @Param: [page, devDataExportTask] <br>
     * @Return: com.hexinfo.dmpro.common.base.PageResult <br>
     * @Description：分页查询<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/7 18:36 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public PageResult queryList(Page page, DevDataExportTask devDataExportTask) {
        LambdaQueryWrapper<DevDataExportTask> wrapper = Wrappers.lambdaQuery();
        wrapper.ne(DevDataExportTask::getDel, CommonConstants.STATUS_DEL);
        if (StrUtil.isNotBlank(devDataExportTask.getTaskCode())) {
            wrapper.like(DevDataExportTask::getTaskCode, devDataExportTask.getTaskCode());
        }
        if (StrUtil.isNotBlank(devDataExportTask.getTaskStatus())) {
            wrapper.eq(DevDataExportTask::getTaskStatus, devDataExportTask.getTaskStatus());
        }
        if (StrUtil.isNotBlank(devDataExportTask.getTaskName())) {
            wrapper.like(DevDataExportTask::getTaskName, devDataExportTask.getTaskName());
        }
        if (StrUtil.isNotBlank(devDataExportTask.getIsDelDataFile())) {
            wrapper.eq(DevDataExportTask::getIsDelDataFile, devDataExportTask.getIsDelDataFile());
        }
        wrapper.orderByDesc(DevDataExportTask::getCreateTime);
        Page returnPage = this.baseMapper.selectPage(page, wrapper);
        queryAfter(returnPage.getRecords());
        return new PageResult(returnPage.getRecords(), returnPage.getTotal());
    }

    private void queryAfter(List<DevDataExportTask> exportTaskList) {
        for (DevDataExportTask exportTask : exportTaskList) {
            // 统计任务数量与状态 ---每次对未完成的做校验， 只有执行中的任务会做状态与数据的刷新
            // 新增加限制项 --- 为防止曾经脏数据，要限制是本周的任务 --判断importTask.getCreateTime()是否在最近七天内
            if (DevDataTransferExportTaskStatusEnum.incomplete.getValue().equals(exportTask.getTaskStatus())
                    && DateUtil.between(exportTask.getCreateTime(), DateUtil.date(), DateUnit.DAY) < 7) {
                List<DevDataExportList> devDataExportLists = devDataExportListService.queryListByTaskCode(exportTask.getTaskCode());
                if (CollectionUtil.isEmpty(devDataExportLists)) {
                    break;
                }
                int exportSuccess = (int) devDataExportLists.stream().filter(s -> DevDataTransferListStatusEnum.SUCCESS.getValue().equals(s.getExportStatus())).count();
                int exportFail = (int) devDataExportLists.stream().filter(s -> DevDataTransferListStatusEnum.FAIL.getValue().equals(s.getExportStatus())).count();
                // 若不存在待执行与执行中状态的 则完成
                boolean isDone = devDataExportLists.stream().noneMatch(s -> DevDataTransferListStatusEnum.TODO.getValue().equals(s.getExportStatus()) || DevDataTransferListStatusEnum.RUNNING.getValue().equals(s.getExportStatus()));
                exportTask.setExportSuccess(exportSuccess);
                exportTask.setExportFail(exportFail);
                exportTask.setTaskStatus(isDone ? DevDataTransferExportTaskStatusEnum.complete.getValue() : DevDataTransferExportTaskStatusEnum.incomplete.getValue());
                // 回显结果并更新数据
                updateById(exportTask);
            }
        }
    }

    /**
     * @Method queryListNoPage
     * @Param
     * @param devDataExportTask
     * @Return java.util.List<com.hexinfo.dmpro.dev.data.transfer.model.DevDataExportTask>
     * @Description 非分页查询
     * @Author Wang zhihao
     * @Date 2024/1/15 9:58
     * @Version V1.0
     */
    @Override
    public List<DevDataExportTask> queryListNoPage(DevDataExportTask devDataExportTask) {
        LambdaQueryWrapper<DevDataExportTask> wrapper = Wrappers.lambdaQuery();
        if (StrUtil.isNotBlank(devDataExportTask.getTaskCode())) {
            wrapper.eq(DevDataExportTask::getTaskCode, devDataExportTask.getTaskCode());
        }
        if (StrUtil.isNotBlank(devDataExportTask.getTaskStatus())) {
            wrapper.eq(DevDataExportTask::getTaskStatus, devDataExportTask.getTaskStatus());
        }
        if (StrUtil.isNotBlank(devDataExportTask.getTaskName())) {
            wrapper.eq(DevDataExportTask::getTaskName, devDataExportTask.getTaskName());
        }
        if (StrUtil.isNotBlank(devDataExportTask.getIsDelDataFile())) {
            wrapper.eq(DevDataExportTask::getIsDelDataFile, devDataExportTask.getIsDelDataFile());
        }
        if (StrUtil.isNotBlank(devDataExportTask.getDel())) {
            wrapper.eq(DevDataExportTask::getDel, devDataExportTask.getDel());
        }
        return this.baseMapper.selectList(wrapper);
    }

    /*
     * @Method: createExportTask <br>
     * @Param: [devDataExportTask] <br>
     * @Return: void <br>
     * @Description：创建导出任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/7 18:36 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void createExportTask(DevDataExportTask devDataExportTask) {
        // ① 获取导出表清单
        List<SourceRuleTableView> exportTableList = getExportTableList(devDataExportTask);
        // ② 过滤黑名单表
        List<SourceRuleTableView> newExportTableList = tableFilter(exportTableList, devDataExportTask.getExportModel());
        // ③ 创建开发数据导出任务
        saveDevDataExportTask(devDataExportTask, newExportTableList.size());
        // ④ 创建导出表任务
        buildExportTaskList(devDataExportTask, newExportTableList);
    }

    private List<SourceRuleTableView> tableFilter(List<SourceRuleTableView> exportTableList, String exportModel) {
        if (StrUtil.equalsAny(exportModel, DevDataExportModelEnum.table.getValue(), DevDataExportModelEnum.custom.getValue())) {
            return exportTableList;
        }
        List<DataTransferTableFilter> dataTransferTableFilters = dataTransferTableFilterService.queryListByType(DataTransferTypeEnum.DEV.getValue());
        if (CollectionUtil.isEmpty(dataTransferTableFilters)) {
            return exportTableList;
        }
        return tableFilter(exportTableList, dataTransferTableFilters);
    }

    private List<SourceRuleTableView> tableFilter(List<SourceRuleTableView> exportTableList, List<DataTransferTableFilter> dataTransferTableFilters) {
        List<String> filterTables = dataTransferTableFilters.stream().map(obj -> obj.getFilterTableKey()).collect(Collectors.toList());
        List<SourceRuleTableView> newExportTableList = new ArrayList<>();
        for (SourceRuleTableView sourceRuleTableView : exportTableList) {
            if (!filterTables.contains(sourceRuleTableView.getDbNameAndTableName())) {
                newExportTableList.add(sourceRuleTableView);
            }
        }
        return newExportTableList;
    }


    private void buildExportTaskList(DevDataExportTask devDataExportTask, List<SourceRuleTableView> exportTableList) {
        for (SourceRuleTableView sourceRuleTableView : exportTableList) {
            devDataExportListService.buildExportTaskList(devDataExportTask, sourceRuleTableView);
        }
    }

    @Override
    public int modifySuccessNumByTaskCode(String taskCode) {
        return devDataExportTaskMapper.modifySuccessNumByTaskCode(taskCode);
    }

    @Override
    public int modifyFailNumByTaskCode(String taskCode) {
        return devDataExportTaskMapper.modifyFailNumByTaskCode(taskCode);
    }

    @Override
    public int reduceSuccessNumByTaskCode(String taskCode) {
        return devDataExportTaskMapper.reduceSuccessNumByTaskCode(taskCode);
    }

    @Override
    public int reduceFailNumByTaskCode(String taskCode) {
        return devDataExportTaskMapper.reduceFailNumByTaskCode(taskCode);
    }

    @Override
    public int modifyStatusByTaskCode(String taskCode, String endTime) {
        return devDataExportTaskMapper.modifyStatusByTaskCode(taskCode, endTime);
    }

    /**
     * @Method removeDataFileById
     * @Param
     * @param id
     * @Return void
     * @Description 根据ID物理删除数据文件
     * @Author Wang zhihao
     * @Date 2024/1/15 14:11
     * @Version V1.0
     */
    @Override
    public void removeDataFileById(String id) {
        try {
            DevDataExportTask devDataExportTask = devDataExportTaskMapper.selectById(id);
            FileTransfer fileTransfer = new FileTransfer("FTP", ftpServer, ftpPort, ftpUserName, ftpPassword);
            fileTransfer.setRemoteDir(devDataExportTask.getFilePath());
            if (!fileTransferService.isFolderExists(fileTransfer)) {
                log.error("目录已删除");
            } else {
                fileTransferService.removeDir(fileTransfer);
            }
            devDataExportTask.setIsDelDataFile("Y");
            this.baseMapper.updateById(devDataExportTask);
            // 删除后统计FTP目录大小
            countFileSize(devDataExportTask.getTaskCode());
        } catch (Exception e) {
            log.error("删除FTP文件发生异常：{}", e.getMessage(), e);
        }
    }

    /**
     * @Method batchRemoveDataFileByIds
     * @Param
     * @param ids
     * @Return void
     * @Description 根据ID批量物理删除数据文件
     * @Author Wang zhihao
     * @Date 2024/1/15 14:07
     * @Version V1.0
     */
    @Override
    public void batchRemoveDataFileByIds(List<String> ids) {
        for (String id : ids) {
            removeDataFileById(id);
        }
    }

    /**
     * @Method logicRemoveDataFileById
     * @Param
     * @param id
     * @Return void
     * @Description 逻辑删除数据文件
     * @Author Wang zhihao
     * @Date 2024/1/15 11:31
     * @Version V1.0
     */
    @Override
    public void logicRemoveDataFileById(String id) {
        LambdaUpdateWrapper<DevDataExportTask> wrapper = Wrappers.lambdaUpdate();
        if (StrUtil.isNotBlank(id)) {
            wrapper.in(DevDataExportTask::getId, id);
        }
        DevDataExportTask devDataExportTask = new DevDataExportTask();
        devDataExportTask.setIsDelDataFile("H");
        update(devDataExportTask, wrapper);
    }

    /**
     * @Method countFileSize
     * @Param
     * @param taskCode
     * @Return void
     * @Description 统计任务完成的ftp文件大小
     * @Author Wang zhihao
     * @Date 2024/1/3 13:20
     * @Version V1.0
     */
    @Override
    public void countFileSize(String taskCode) {
        DevDataExportTask devDataExportTask = queryByTaskCode(taskCode);
        FileTransfer fileTransfer = new FileTransfer("FTP", ftpServer, ftpPort, ftpUserName, ftpPassword);
        fileTransfer.setRemoteDir(devDataExportTask.getFilePath());
        Double fileSize = fileTransferService.getDirSize(fileTransfer);
        // 存储字节
        devDataExportTask.setFileSize(fileSize);
        updateById(devDataExportTask);
    }

    @Override
    public void batchLogicRemoveDataFileById(List<String> ids) {
        for (String id : ids) {
            logicRemoveDataFileById(id);
        }
    }

    @Override
    public DevDataExportTask queryByTaskCode(String taskCode) {
        LambdaQueryWrapper<DevDataExportTask> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(DevDataExportTask::getTaskCode, taskCode);
        return this.baseMapper.selectOne(wrapper);
    }

    /*
     * @Method: importFromExcel <br>
     * @Param: [multipartFile] <br>
     * @Return: java.lang.String <br>
     * @Description：上传开发数据导出表清单文件<br>
     * @Author： wz.li<br>
     * @Date： 2023/12/5 16:57 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public String importFromExcel(MultipartFile multipartFile) {
        if (multipartFile.isEmpty()) {
            return null;
        }
        File localFile = FileTransferUtil.saveFile(multipartFile, tempPath);
        return localFile.getPath();
    }

    /*
     * @Method: continueRunById <br>
     * @Param: [id] <br>
     * @Return: void <br>
     * @Description：重新加载开发数据导出任务清单<br>
     * @Author： wz.li<br>
     * @Date： 2023/12/5 16:57 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void continueRunById(String id) {
        DevDataExportTask devDataExportTask = this.baseMapper.selectById(id);
        List<DevDataExportList> devDataExportLists = devDataExportListService.queryListByTaskCode(devDataExportTask.getTaskCode());
        for (DevDataExportList devDataExportList : devDataExportLists) {
            if (DevDataTransferListStatusEnum.TODO.getValue().equals(devDataExportList.getExportStatus())) {
                devDataExportHandler.executeExportTask(devDataExportList);
            } else if (DevDataTransferListStatusEnum.RUNNING.getValue().equals(devDataExportList.getExportStatus())) {
                devDataExportListService.updateByRestart(devDataExportList.getId());
                devDataExportHandler.executeExportTask(devDataExportList);
            }
        }
    }

    /*
     * @Method: suspend <br>
     * @Param: [ids] <br>
     * @Return: void <br>
     * @Description：暂停指定的开发数据导出任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/12/5 16:58 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    @Transactional
    public void suspend(List<String> ids) {
        for (String id : ids) {
            DevDataExportTask devDataExportTask = this.baseMapper.selectById(id);
            if (DevDataTransferExportTaskStatusEnum.incomplete.getValue().equals(devDataExportTask.getTaskStatus())) {
                devDataExportTask.setTaskStatus(DevDataTransferExportTaskStatusEnum.suspend.getValue());
                this.baseMapper.updateById(devDataExportTask);
            }
        }
    }

    /**
     * @Method abolish
     * @Param
     * @param ids
     * @Return void
     * @Description 中止指定的开发数据导出任务
     * @Author Wang zhihao
     * @Date 2024/1/3 18:42
     * @Version V1.0
     */
    @Override
    @Transactional
    public void abolish(List<String> ids) {
        for (String id : ids) {
            DevDataExportTask devDataExportTask = this.baseMapper.selectById(id);
            if (StrUtil.equalsAny(devDataExportTask.getTaskStatus(), DevDataTransferExportTaskStatusEnum.incomplete.getValue(), DevDataTransferExportTaskStatusEnum.suspend.getValue())) {
                // 将任务状态更改为中止
                devDataExportTask.setTaskStatus(DevDataTransferExportTaskStatusEnum.abolish.getValue());
                this.baseMapper.updateById(devDataExportTask);
                // 更新所有任务清单状态为中止
                devDataExportListService.abolishByTaskCode(devDataExportTask.getTaskCode());
            }
        }
    }

    /*
     * @Method: restart <br>
     * @Param: [ids] <br>
     * @Return: void <br>
     * @Description：开发数据导出任务暂停后重启<br>
     * @Author： wz.li<br>
     * @Date： 2023/12/5 17:02 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    @Transactional
    public void restart(List<String> ids) {
        for (String id : ids) {
            DevDataExportTask devDataExportTask = this.baseMapper.selectById(id);
            if (DevDataTransferExportTaskStatusEnum.suspend.getValue().equals(devDataExportTask.getTaskStatus())) {
                devDataExportTask.setTaskStatus(DevDataTransferExportTaskStatusEnum.incomplete.getValue());
                this.baseMapper.updateById(devDataExportTask);
            }
        }
    }

    /**
     * @Method reset
     * @Param ids
     * @Return void
     * @Description 开发数据导出任务刷新
     * @Author Yin.Yang
     * @Date 2023/12/26 19:35
     * @Version V1.0
     */
    @Override
    @Transactional
    public void reset(List<String> ids) {
        for (String id : ids) {
            DevDataExportTask devDataExportTask = this.baseMapper.selectById(id);
            String filePath = devDataExportTask.getFilePath();
            if (StrUtil.isNotBlank(filePath)) {
                FileTransfer fileTransfer = new FileTransfer("FTP", ftpServer, ftpPort, ftpUserName, ftpPassword);
                fileTransfer.setRemoteDir(filePath);
                Double fileSize = fileTransferService.getDirSize(fileTransfer);
                devDataExportTask.setFileSize(fileSize);
                this.baseMapper.updateById(devDataExportTask);
            }
        }
    }

    /**
     * @Method countFtpTakeUp
     * @Param
     * @Return void
     * @Description 统计FTP空间占用
     * @Author Wang zhihao
     * @Date 2024/1/3 14:56
     * @Version V1.0
     */
    @Override
    public FtpTakeUp countFtpTakeUp() {
        FtpTakeUp ftpTakeUp = new FtpTakeUp();
        LambdaQueryWrapper<DevDataExportTask> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(DevDataExportTask::getIsDelDataFile, "N");
        List<DevDataExportTask> devDataExportTasks = this.baseMapper.selectList(wrapper);
        double takeUp = devDataExportTasks.stream().mapToDouble(s -> s.getFileSize() == null ? 0 : s.getFileSize()).sum();
        double takeUpWithGb = NumberUtil.round(takeUp / (1024.0 * 1024.0 * 1024), 2).doubleValue();
        if (takeUpWithGb < 1024) {
            ftpTakeUp.setTotalSpace(Double.parseDouble(ftpSpace))
                    .setTakeUpSpace(takeUpWithGb)
                    .setTakeUpUnit("GB");
        } else {
            ftpTakeUp.setTotalSpace(Double.parseDouble(ftpSpace))
                    .setTakeUpSpace(Math.round((takeUpWithGb / 1024.0) * 100.0 / 100.0))
                    .setTakeUpUnit("TB");
        }
        return ftpTakeUp;
    }

    /**
     * @Method removeByIds
     * @Param
     * @param ids
     * @Return void
     * @Description 根据ID删除任务及FTP文件
     * @Author Wang zhihao
     * @Date 2024/1/3 17:48
     * @Version V1.0
     */
    @Override
    public void removeByIds(List<String> ids) {
        for (String id : ids) {
            // 删除任务
            deleteById(id);
        }
    }

    /**
     * @Method deleteById
     * @Param
     * @param id
     * @Return void
     * @Description 根据Id删除任务
     * @Author Wang zhihao
     * @Date 2024/1/11 18:12
     * @Version V1.0
     */
    @Override
    public void deleteById(String id) {
        // 删除list清单
        LambdaQueryWrapper<DevDataExportTask> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(DevDataExportTask::getId, id);
        DevDataExportTask devDataExportTask = getOne(wrapper);
        // 清单逻辑删除
        devDataExportListService.logicRemoveByTaskCode(devDataExportTask.getTaskCode());
        // 删除任务
        updateById(new DevDataExportTask().setId(id).setIsDelDataFile("H").setDel("1"));
    }

    /*
     * @Method: saveDevDataExportTask <br>
     * @Param: [devDataExportTask] <br>
     * @Return: void <br>
     * @Description：保存导出任务信息<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/7 18:36 <br>
     * @Version： V2.0.2<br>
     */
    private void saveDevDataExportTask(DevDataExportTask devDataExportTask, Integer total) {
        if ("increment".equals(devDataExportTask.getExportType())) {
            List<String> dateList = devDataExportTask.getDateList();
            devDataExportTask.setExportTimeInterval(dateList.get(0) + "--" + dateList.get(1));
        }
        devDataExportTask.setTaskCode(DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss"));
        devDataExportTask.setTaskStatus(DevDataTransferExportTaskStatusEnum.incomplete.getValue());
        devDataExportTask.setStartTime(DateUtil.date());
        devDataExportTask.setExportTotal(total);
        devDataExportTask.setExportSuccess(0);
        devDataExportTask.setExportFail(0);
        devDataExportTask.setIsDelDataFile("N");
        devDataExportTask.setFilePath(devDataExportTask.getFilePath() + "/" + devDataExportTask.getTaskCode());
        this.save(devDataExportTask);
    }

    /*
     * @Method: getExportTableList <br>
     * @Param: [devDataExportTask] <br>
     * @Return: java.util.List<com.hexinfo.dmpro.data.transfer.common.model.SourceRuleTableView> <br>
     * @Description：获取导出表清单<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/23 16:50 <br>
     * @Version： V2.0.2<br>
     */
    private List<SourceRuleTableView> getExportTableList(DevDataExportTask devDataExportTask) {
        switch (DevDataExportModelEnum.valueOf(devDataExportTask.getExportModel())) {
            case database:
                return createExportListByDatabase(devDataExportTask);
            case table:
                return createExportListByTable(devDataExportTask);
            case custom:
                return createExportListByCustom(devDataExportTask);
            default:
                throw new RuntimeException("不支持导出模式：" + devDataExportTask.getExportModel());
        }
    }

    /*
     * @Method: createExportListBySource <br>
     * @Param: [devDataExportTask] <br>
     * @Return: java.lang.Integer <br>
     * @Description：根据源创建导出任务清单<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/7 18:37 <br>
     * @Version： V2.0.2<br>
     */
    private List<SourceRuleTableView> createExportListBySource(DevDataExportTask devDataExportTask) {
        List<SourceRuleTableView> sourceRuleTableViews = sourceRuleTableViewService.queryTableListBySource(devDataExportTask.getSourceName());
        if (CollectionUtil.isEmpty(sourceRuleTableViews)) {
            throw new RuntimeException(StrUtil.format("根据源【{}】没有找到对应的表", devDataExportTask.getSourceName()));
        }
        Map<String, List<SourceRuleTableView>> sourceRuleTableViewMap = classifyRuleTableView(sourceRuleTableViews);
        return mergeSourceRuleTableView(sourceRuleTableViewMap);
    }

    private Map<String, List<SourceRuleTableView>> classifyRuleTableView(List<SourceRuleTableView> sourceRuleTableViews) {
        Map<String, List<SourceRuleTableView>> sourceRuleTableViewMap = new HashMap<>();
        for (SourceRuleTableView sourceRuleTableView : sourceRuleTableViews) {
            List<SourceRuleTableView> sourceRuleTableViewList = new ArrayList<>();
            if (sourceRuleTableViewMap.containsKey(sourceRuleTableView.getDbNameAndTableName())) {
                sourceRuleTableViewList = sourceRuleTableViewMap.get(sourceRuleTableView.getDbNameAndTableName());
            }
            sourceRuleTableViewList.add(sourceRuleTableView);
            sourceRuleTableViewMap.put(sourceRuleTableView.getDbNameAndTableName(), sourceRuleTableViewList);
        }
        return sourceRuleTableViewMap;
    }

    private List<SourceRuleTableView> mergeSourceRuleTableView(Map<String, List<SourceRuleTableView>> sourceRuleTableViewMap) {
        List<SourceRuleTableView> mergeSourceRuleTableViews = new ArrayList<>();
        for (String dbNameAndTableName : sourceRuleTableViewMap.keySet()) {
            List<SourceRuleTableView> sourceRuleTableViewList = sourceRuleTableViewMap.get(dbNameAndTableName);
            SourceRuleTableView sourceRuleTableView = sourceRuleTableViewList.get(0);
            List<String> sourceValues = new ArrayList<>();
            for (SourceRuleTableView ruleTableView : sourceRuleTableViewList) {
                if ("1".equals(ruleTableView.getDateIndex()) && StrUtil.isNotBlank(ruleTableView.getPartValue2())) {
                    sourceValues.add(ruleTableView.getPartValue2());
                } else if ("2".equals(ruleTableView.getDateIndex()) && StrUtil.isNotBlank(ruleTableView.getPartValue1())) {
                    sourceValues.add(ruleTableView.getPartValue1());
                } else if (StrUtil.isNotBlank(ruleTableView.getPartValue1())) {
                    sourceValues.add(ruleTableView.getPartValue1());
                } else if (StrUtil.isNotBlank(ruleTableView.getPartValue2())) {
                    sourceValues.add(ruleTableView.getPartValue2());
                }
            }
            sourceRuleTableView.setSourceValues(sourceValues);
        }
        return mergeSourceRuleTableViews;
    }

    /*
     * @Method: createExportListByDatabase <br>
     * @Param: [devDataExportTask] <br>
     * @Return: java.lang.Integer <br>
     * @Description：根据库创建导出任务清单<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/7 18:37 <br>
     * @Version： V2.0.2<br>
     */
    private List<SourceRuleTableView> createExportListByDatabase(DevDataExportTask devDataExportTask) {
        List<SourceRuleTableView> sourceRuleTableViews = new ArrayList<>();
        // 从源数据库获取所有表名
        List<String> tableNameList = getTableNameList(devDataExportTask.getDatabaseName());
        for (String tableName : tableNameList) {
            SourceRuleTableView sourceRuleTableView = getPartitionInfoByTable(devDataExportTask.getDatabaseName(), tableName);
            sourceRuleTableViews.add(sourceRuleTableView);
        }
        if ("increment".equals(devDataExportTask.getExportType())) {
            sourceRuleTableViews = sourceRuleTableViews.stream().filter(s -> s.getDatePartitionName() != null && !s.getDatePartitionName().isEmpty()).collect(Collectors.toList());
        } else if ("complete".equals(devDataExportTask.getExportType())) {
            sourceRuleTableViews = sourceRuleTableViews.stream().filter(s -> s.getDatePartitionName() == null || s.getDatePartitionName().isEmpty()).collect(Collectors.toList());
        }
        return sourceRuleTableViews;
    }

    private SourceRuleTableView getPartitionInfoByTable(String databaseName, String tableName) {
        SourceRuleTableView sourceRuleTableView = new SourceRuleTableView();
        List<CdhFieldEntity> partitionList = cdhMetadataService.queryPartitionList(databaseName, tableName);
        DateParatitionFieldMatching dateParatitionFieldMatching = datePartitionFieldMatchingService.queryByParatitionList(partitionList);
        sourceRuleTableView.setTblDatabaseName(databaseName).setTblName(tableName);
        if (dateParatitionFieldMatching != null) {
            sourceRuleTableView.setDatePartitionName(dateParatitionFieldMatching.getTimeFieldKay()).setDatePartitionFormat(dateParatitionFieldMatching.getTimeFieldValue());
        }
        return sourceRuleTableView;
    }

    /*
     * @Method: queryTableListByDatabase <br>
     * @Param: [databaseName] <br>
     * @Return: java.util.Map<java.lang.String,com.hexinfo.dmpro.data.transfer.common.model.SourceRuleTableView> <br>
     * @Description：根据数据库名称查询所有表, 存在一个表多个源分区值时，会有多条记录，按库同步则多条记录中取一条即可<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/24 17:51 <br>
     * @Version： V2.0.2<br>
     */
    private Map<String, SourceRuleTableView> queryTableListByDatabase(String databaseName) {
        Map<String, SourceRuleTableView> sourceRuleTableViewMap = new HashMap<>();
        List<SourceRuleTableView> sourceRuleTableViews = sourceRuleTableViewService.queryTableListByDatabase(databaseName);
        for (SourceRuleTableView sourceRuleTableView : sourceRuleTableViews) {
            if (!sourceRuleTableViewMap.containsKey(sourceRuleTableView.getDbNameAndTableName())) {
                sourceRuleTableViewMap.put(sourceRuleTableView.getDbNameAndTableName(), sourceRuleTableView);
            }
        }
        return sourceRuleTableViewMap;
    }

    /*
     * @Method: getTableNameList <br>
     * @Param: [devDataExportTask] <br>
     * @Return: java.util.List<java.lang.String> <br>
     * @Description：查询指定库下所有表<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/24 17:54 <br>
     * @Version： V2.0.2<br>
     */
    private List<String> getTableNameList(String databaseName) {
        List<CdhTblsEntity> tableNameList = cdhMetadataService.queryTableListByDatabase(databaseName);
        if (CollectionUtil.isEmpty(tableNameList)) {
            throw new RuntimeException(StrUtil.format("根据数据库名【{}】没有找到对应的表", databaseName));
        }
        return tableNameList.stream().map(CdhTblsEntity::getTblName).collect(Collectors.toList());
    }

    /*
     * @Method: createExportListByTable <br>
     * @Param: [devDataExportTask] <br>
     * @Return: java.lang.Integer <br>
     * @Description：根据库表创建导出任务清单<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/7 18:38 <br>
     * @Version： V2.0.2<br>
     */
    private List<SourceRuleTableView> createExportListByTable(DevDataExportTask devDataExportTask) {
        List<SourceRuleTableView> sourceRuleTableViews = new ArrayList<>();
        for (String tableName : devDataExportTask.getTableNameList()) {
            SourceRuleTableView sourceRuleTableView = getPartitionInfoByTable(devDataExportTask.getDatabaseName(), tableName);
            sourceRuleTableViews.add(sourceRuleTableView);
        }
        return sourceRuleTableViews;
    }

    /*
     * @Method: getSourceRuleTableViews <br>
     * @Param: [devDataExportTask] <br>
     * @Return: java.util.List<com.hexinfo.dmpro.data.transfer.common.model.SourceRuleTableView> <br>
     * @Description：获取导出库表的元数据元数据视图<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/16 14:38 <br>
     * @Version： V2.0.2<br>
     */
    private List<SourceRuleTableView> getSourceRuleTableViews(DevDataExportTask devDataExportTask) {
        List<SourceRuleTableView> sourceRuleTableViews = new ArrayList<>();
        for (String tableName : devDataExportTask.getTableNameList()) {
            sourceRuleTableViews.add(queryByDbNameAndTableNameGroup(devDataExportTask.getDatabaseName(), tableName));
        }
        return sourceRuleTableViews;
    }

    /*
     * @Method: queryByDbNameAndTableNameGroup <br>
     * @Param: [databaseName, tableName] <br>
     * @Return: com.hexinfo.dmpro.data.transfer.common.model.SourceRuleTableView <br>
     * @Description：根据库表查询对应的元数据视图<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/16 14:38 <br>
     * @Version： V2.0.2<br>
     */
    private SourceRuleTableView queryByDbNameAndTableNameGroup(String databaseName, String tableName) {
        List<SourceRuleTableView> sourceRuleTableViews = sourceRuleTableViewService.queryByDbNameAndTableName(databaseName, tableName);
        if (CollectionUtil.isNotEmpty(sourceRuleTableViews)) {
            return sourceRuleTableViews.get(0);
        } else {
            return new SourceRuleTableView().setTblDatabaseName(databaseName).setTblName(tableName);
        }
    }

    /*
     * @Method: createExportListByCustom <br>
     * @Param: [devDataExportTask] <br>
     * @Return: java.lang.Integer <br>
     * @Description：根据自定义清单创建导出任务清单<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/7 18:38 <br>
     * @Version： V2.0.2<br>
     */
    private List<SourceRuleTableView> createExportListByCustom(DevDataExportTask devDataExportTask) {
        if (!FileUtil.exist(devDataExportTask.getCustomTableListPath())) {
            throw new RuntimeException("自定义清单文件不存在");
        }
        List<DevDataExportCustomList> devDataExportCustomLists = getExcelData(new File(devDataExportTask.getCustomTableListPath()));
        if (CollectionUtil.isEmpty(devDataExportCustomLists)) {
            throw new RuntimeException("自定义清单内容为空");
        }
        return devDataExportCustomListConverter(devDataExportCustomLists);
    }

    private List<DevDataExportCustomList> getExcelData(File file) {
        ExcelImportResult<DevDataExportCustomList> convertAfterList = readExcel(file);
        if (CollectionUtil.isNotEmpty(convertAfterList.getFailList())) {
            StringBuffer sb = new StringBuffer();
            for (DevDataExportCustomList p : convertAfterList.getFailList()) {
                sb.append("第" + (p.getRowNum() + 1) + "行的错误是：\n" + p.getErrorMsg().replaceAll(",", "\n")).append("\n");
            }
            throw new RuntimeException(sb.toString());
        }
        return convertAfterList.getList();
    }

    private ExcelImportResult<DevDataExportCustomList> readExcel(File file) {
        ImportParams importParams = new ImportParams();
        importParams.setNeedVerify(false);//开启校验
        return ExcelImportUtil.importExcelMore(file, DevDataExportCustomList.class, importParams);
    }

    private List<SourceRuleTableView> devDataExportCustomListConverter(List<DevDataExportCustomList> devDataExportCustomLists) {
        List<SourceRuleTableView> sourceRuleTableViews = new ArrayList<>();
        for (DevDataExportCustomList devDataExportCustomList : devDataExportCustomLists) {
            if (StrUtil.isNotBlank(devDataExportCustomList.getDbName()) && StrUtil.isNotBlank(devDataExportCustomList.getTableName())) {
                // 获取指定表的所有分区信息
                SourceRuleTableView sourceRuleTableView = getPartitionInfoByTable(devDataExportCustomList.getDbName(), devDataExportCustomList.getTableName());
                String where = devDataExportCustomList.getCustomWhere();
                if (StrUtil.isNotBlank(where) && !where.trim().toLowerCase().equals("where")) {
                    sourceRuleTableView.setCustomWhere(devDataExportCustomList.getCustomWhere());
                }
                sourceRuleTableViews.add(sourceRuleTableView);
            }
        }
        return sourceRuleTableViews;
    }
}
